package com.ht.callback.controller;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.ht.api.db.Entity;
import com.ht.api.db.util.RedisUtil;
import com.ht.callback.constant.CacheConstants;
import com.ht.callback.function.Function;
import com.ht.callback.kafka.KafkaProducer;
import com.ht.callback.util.FunctionUtil;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;

/**
 * 通用回调接口类
 * @author asq
 * @createTime 2024年12月18日 20:32:08
 */
@RestController
@RequestMapping("/callback/{appid}")
@Slf4j
public class CallbackController {
	/** 回调事件的topic */
	private static final String TOPIC_CALLBACK = "callback";
	@Autowired
	private KafkaProducer kafkaProducer;
	@Resource
	private Function defaultFunction;
	
	@GetMapping(produces = "text/plain;charset=utf-8")
	public String get(@PathVariable String appid, @RequestParam(required = false) Map<String, String> params,
			@RequestBody(required = false) String body) {
	    // url参数转JSONObject
	    JSONObject paramUrl = new JSONObject();
        if (params != null) {
        	paramUrl.putAll(params);
        }
	    return handleRequest(appid, paramUrl, body);
	}

	@PostMapping(produces = "application/xml; charset=UTF-8")
	public String post(@PathVariable String appid,
			@RequestParam(required = false) Map<String, String> params,
			@RequestBody(required = false) String body) {
	    // url参数转JSONObject
	    JSONObject paramUrl = new JSONObject();
        if (params != null) {
        	paramUrl.putAll(params);
        }
	    
	    // 统一使用paramJson处理业务逻辑
	    return handleRequest(appid, paramUrl, body);
	}
	
	/**
	 * 统一处理外部回调请求
	 * @param appid 应用ID
	 * @param paramUrl url参数
	 * @param body body参数
	 * @return
	 */
	private String handleRequest(String appid, JSONObject paramUrl, String body) {
		log.info("[callback]收到回调：appid:{},paramUrl:{},body:{}", appid, JSONUtil.toJsonStr(paramUrl), body);
		// 1. 查找appid对应的平台，判断本次访问的目的是校验接口还是真正的业务回调；
		JSONObject platformConfig = getPlatformConfig(appid);
		JSONObject appConfig = getAppConfig(appid);
		boolean validate = platformConfig.getByPath("callback.validate", Boolean.class);

		if (validate) {
			// 2. 如果是校验接口，则执行对应平台的[激活函数]，返回结果；
			return doValidate(platformConfig, appConfig, appid, paramUrl, body);
		} else {
			// 3. 如果是真正的回调接口，则执行对应平台的[验签函数]，获取解密后的明文数据；
			return doCallback(platformConfig, appConfig, appid, paramUrl, body);
		}
	}

	/**
	 * 首次接入时返回校验信息
	 * @param platformConfig 平台配置
	 * @param appConfig app配置
	 * @param appid 应用ID
	 * @param params 回调参数
	 */
	private String doValidate(JSONObject platformConfig, JSONObject appConfig, String appid, JSONObject paramUrl, String body) {
		return getFunction(platformConfig).active(appConfig, paramUrl, body);
	}

	/**
	 * 正式接入后处理回调通知
	 * @param platformConfig 平台配置
	 * @param appConfig app配置
	 * @param appid 应用ID
	 * @param params 回调参数
	 */
	private String doCallback(JSONObject platformConfig, JSONObject appConfig, String appid, JSONObject paramUrl, String body) {
		// 1. 验签，确定来源是否合法
		Function function = getFunction(platformConfig);
		String data = function.verifySign(appConfig, paramUrl, body);
		
		// 2. 将数据按一定规则写入mq;
		if (StrUtil.isNotBlank(data)) {
			sendToMq(appid, data);
		}

		// 3. 执行对应平台的[返回函数]，获取返回值，返回给第三方平台。
		return function.result(paramUrl, body);
	}

	/**
	 * 获取对应平台的函数实现类
	 * @param platformConfig 平台配置规则
	 * @return
	 */
	private Function getFunction(JSONObject platformConfig) {
		String key = platformConfig.getByPath("callback.func", String.class);
		Function function = FunctionUtil.getFunction(key);
		return function != null ? function : defaultFunction;
	}
	
	/**
	 * 将数据按一定规则写入mq
	 * @param appid
	 * @param params
	 */
	private void sendToMq(String appid, String params) {
		// 生成kafka消息
		JSONObject json = JSONUtil.createObj();
		json.set("appid", appid);
		json.set("data", params);
		String data = JSONUtil.toJsonStr(json);
		
		// 写入kafka
		kafkaProducer.sendMessage(TOPIC_CALLBACK, data);
	}

	/**
	 * 获取平台配置
	 * @param appid 应用ID
	 * @return
	 */
	private JSONObject getPlatformConfig(String appid) {
		// 从缓存中获取平台配置
		Entity entity = RedisUtil.get(CacheConstants.KEY_APP + appid);
		return RedisUtil.get(CacheConstants.KEY_PLATFORM + entity.getStr("pid"));
	}

	/**
	 * 获取应用配置
	 * @param appid 应用ID
	 * @return
	 */
	private JSONObject getAppConfig(String appid) {
		// 从缓存中获取平台配置
		Entity entity = RedisUtil.get(CacheConstants.KEY_APP + appid);
		return JSONUtil.parseObj(entity.getStr("config"));
	}
}
